% load_graph.m
% 从CSV文件加载节点和边的数据，构建图结构体。
% 对应 C++ 版本中的 Graph 类加载功能。
%
% @输入:
%   nodes_csv_path (string): 节点CSV文件的路径。
%   edges_csv_path (string): 边CSV文件的路径。
% @输出:
%   graph (struct): 包含图所有信息的结构体。
%     .nodes (struct array): 存储所有节点的数据。
%     .adj_list (cell array): 邻接表 (后继节点)。
%     .predecessors_list (cell array): 前驱节点列表。
%     .num_nodes (int): 节点总数。
%   code_map (struct): 存储操作和类型代码的结构体。

function [graph, code_map] = load_graph(nodes_csv_path, edges_csv_path)

    % --- 1. 初始化结构体模板 ---
    
    % 对应 C++ 的 CodeMap 结构体
    code_map = struct('ALLOC', 0, 'FREE', 0, 'L1', 0, 'UB', 0, 'L0A', 0, 'L0B', 0, 'L0C', 0);
    
    % 对应 C++ 的 NodeData 结构体
    node_template = struct(...
        'id', [], ...
        'op', '', ...
        'buf_id', [], ...
        'size', [], ...
        'type', '', ...
        'pipe', '', ...
        'cycles', [], ...
        'bufs', [], ...
        'op_code', 0, ...
        'type_code', 0 ...
    );

    % --- 2. 加载和解析节点文件 (Nodes.csv) ---
    
    % 使用 readtable 读取CSV，它可以很好地处理混合数据类型和空值
    opts = detectImportOptions(nodes_csv_path);
    opts.VariableNamingRule = 'preserve'; % 保留原始列名大小写
    nodes_table = readtable(nodes_csv_path, opts);
    
    raw_nodes_data = [];
    op_map = containers.Map('KeyType', 'char', 'ValueType', 'int32');
    type_map = containers.Map('KeyType', 'char', 'ValueType', 'int32');
    op_counter = 1;
    type_counter = 1;
    max_id = 0;

    fprintf('开始解析节点文件: %s\n', nodes_csv_path);
    for i = 1:height(nodes_table)
        current_node = node_template;
        
        % C++ 代码中所有ID都+1，这里保持一致
        % *** 已修正: 使用正确的列名 'Id' ***
        node_id = nodes_table.Id(i) + 1;
        current_node.id = node_id;
        if node_id > max_id
            max_id = node_id;
        end

        % *** 已修正: 使用正确的列名 'Op' ***
        current_node.op = strtrim(char(nodes_table.Op{i}));
        
        % 处理 optional<int> 类型
        % *** 已修正: 使用正确的列名 'BufId' ***
        if ~isnan(nodes_table.BufId(i))
            current_node.buf_id = nodes_table.BufId(i);
        end
        
        % 处理 optional<long long> 类型
        % *** 已修正: 使用正确的列名 'Size' ***
        if ~isnan(nodes_table.Size(i))
            current_node.size = nodes_table.Size(i);
        end

        % *** 已修正: 使用正确的列名 'Type' 和 'Pipe' ***
        current_node.type = strtrim(char(nodes_table.Type{i}));
        current_node.pipe = strtrim(char(nodes_table.Pipe{i}));

        % *** 已修正: 使用正确的列名 'Cycles' ***
        if ismember('Cycles', nodes_table.Properties.VariableNames) && ~isnan(nodes_table.Cycles(i))
            current_node.cycles = nodes_table.Cycles(i);
        end

        % 处理 bufs 字段 (空格或逗号分隔的数字字符串)
        % *** 已修正: 使用正确的列名 'Bufs' ***
        if ismember('Bufs', nodes_table.Properties.VariableNames) && iscell(nodes_table.Bufs)
            bufs_val = nodes_table.Bufs{i};
            % 确保我们只处理字符类型的数据
            if ischar(bufs_val)
                bufs_str = strtrim(bufs_val);
                if ~isempty(bufs_str)
                    % *** 已修正: 将逗号替换为空格以正确解析 "5,3" ***
                    bufs_str_fixed = strrep(bufs_str, ',', ' ');
                    current_node.bufs = str2num(bufs_str_fixed); %#ok<ST2NM>
                end
            end
        end
        
        raw_nodes_data = [raw_nodes_data; current_node];
        
        % 构建 op_map 和 type_map
        if ~isempty(current_node.op) && ~isKey(op_map, current_node.op)
            op_map(current_node.op) = op_counter;
            op_counter = op_counter + 1;
        end
        if ~isempty(current_node.type) && ~isKey(type_map, current_node.type)
            type_map(current_node.type) = type_counter;
            type_counter = type_counter + 1;
        end
    end
    fprintf('节点文件解析完成，共 %d 个原始节点记录。\n', length(raw_nodes_data));

    % --- 3. 填充 code_map 和最终的 nodes 结构体数组 ---
    
    if isKey(op_map, 'ALLOC'); code_map.ALLOC = op_map('ALLOC'); end
    if isKey(op_map, 'FREE'); code_map.FREE = op_map('FREE'); end
    if isKey(type_map, 'L1'); code_map.L1 = type_map('L1'); end
    if isKey(type_map, 'UB'); code_map.UB = type_map('UB'); end
    if isKey(type_map, 'L0A'); code_map.L0A = type_map('L0A'); end
    if isKey(type_map, 'L0B'); code_map.L0B = type_map('L0B'); end
    if isKey(type_map, 'L0C'); code_map.L0C = type_map('L0C'); end
    
    % 预分配结构体数组以提高效率，并确保索引与ID对应
    nodes(max_id) = node_template;
    for i = 1:length(raw_nodes_data)
       raw_node = raw_nodes_data(i);
       node_idx = raw_node.id;
       
       % 填充 op_code 和 type_code
       if ~isempty(raw_node.op) && isKey(op_map, raw_node.op)
           raw_node.op_code = op_map(raw_node.op);
       end
       if ~isempty(raw_node.type) && isKey(type_map, raw_node.type)
           raw_node.type_code = type_map(raw_node.type);
       end
       nodes(node_idx) = raw_node;
    end
    
    graph.nodes = nodes;
    graph.num_nodes = max_id;

    % --- 4. 加载和解析边文件 (Edges.csv) ---
    
    fprintf('开始解析边文件: %s\n', edges_csv_path);
    edges_matrix = readmatrix(edges_csv_path);
    
    % 初始化邻接表和前驱列表 (使用元胞数组)
    adj_list = cell(graph.num_nodes, 1);
    predecessors_list = cell(graph.num_nodes, 1);
    
    for i = 1:size(edges_matrix, 1)
        % C++ 代码中所有ID都+1，这里保持一致
        start_node = edges_matrix(i, 1) + 1;
        end_node = edges_matrix(i, 2) + 1;
        
        if start_node <= graph.num_nodes && end_node <= graph.num_nodes
            % 添加到后继列表
            adj_list{start_node} = [adj_list{start_node}, end_node];
            % 添加到前驱列表
            predecessors_list{end_node} = [predecessors_list{end_node}, start_node];
        end
    end
    
    graph.adj_list = adj_list;
    graph.predecessors_list = predecessors_list;
    fprintf('边文件解析完成。\n');
    
end